package com.huxi.lang.text;

import java.util.ArrayList;
import java.util.Objects;

/**
 * 消息模板内容变量替换构建器
 * 
 * @author jian.wu
 *
 */
public class MessageFormatter {

	protected static class CompIndex {
		protected final String comp;
		protected final int index;

		private CompIndex(String comp, int index) {
			this.comp = comp;
			this.index = index;
		}
	}

	private static final int NO_VAR_REPLACE = -1;

	private final String pattern;
	private final CompIndex[] comps;
	private final boolean quiet;

	private MessageFormatter(String pattern, CompIndex[] comps, boolean quiet) {
		this.pattern = pattern;
		this.comps = comps;
		this.quiet = quiet;
	}

	public String getPattern() {
		return pattern;
	}

	public boolean isMutable() {
		return comps != null;
	}

	/**
	 * 格式化消息模板内容，替换变量内容
	 * 
	 * @param args 变量数组
	 * @return 消息模板变量替换后内容
	 * @throws IllegalArgumentException 替换变量内容失败
	 */
	public String build(Object[] args) throws IllegalArgumentException {
		if (comps == null) {
			return pattern;
		}
		final StringBuilder sb = new StringBuilder(128);
		final int len = args != null ? args.length : 0;
		for (CompIndex item : comps) {
			int ii = item.index;
			if (ii == NO_VAR_REPLACE) {
				sb.append(item.comp);
			} else if (ii < len) {
				sb.append(args[ii]);
			} else {
				if (quiet) {
					sb.append('{').append(ii).append('}');
				} else {
					throw new IllegalArgumentException("消息模板内容替换变量失败，不存在的数组变量索引 = " + ii);
				}
			}
		}
		return sb.toString();
	}

	protected static final int B_CHAR = '{';
	protected static final int E_CHAR = '}';

	/**
	 * 创建消息模板格式化处理器
	 * 
	 * @param pattern 模板内容，非空值。
	 * @param quiet   是否安静模式，安静模式不抛出异常。
	 * @return 格式化处理器，非空值。
	 * @throws IllegalArgumentException 模板内容解析失败
	 */
	public static MessageFormatter of(String pattern, boolean quiet) throws IllegalArgumentException {
		Objects.requireNonNull(pattern, "消息模板不能为空值");
		int start = pattern.indexOf(B_CHAR);
		if (start == -1) {
			// 消息模板不存在变量界定符{}
			return new MessageFormatter(pattern, null, quiet);
		}
		ArrayList<CompIndex> comps = new ArrayList<>();
		int offset = 0;
		int first = 0;
		while (start != -1) {
			int next = pattern.indexOf(E_CHAR, start);
			if (next == -1) {
				break;
			}
			if (start != offset) {
				comps.add(new CompIndex(pattern.substring(offset, start), NO_VAR_REPLACE));
			}
			String num = pattern.substring(start + 1, next).trim();
			if (num.length() == 0) {
				comps.add(new CompIndex("", first));
				first++;
			} else {
				try {
					int nn = Integer.parseInt(num);
					if (nn >= 0) {
						comps.add(new CompIndex("", nn));
					} else {
						if (quiet) {
							comps.add(new CompIndex(pattern.substring(start, next + 1), NO_VAR_REPLACE));
						} else {
							throw new IllegalArgumentException("消息模板未匹配变量索引必须为正整数{index} = " + num);
						}
					}
				} catch (NumberFormatException en) {
					if (quiet) {
						// 非有效数字索引
						comps.add(new CompIndex(pattern.substring(start, next + 1), NO_VAR_REPLACE));
					} else {
						throw new IllegalArgumentException("消息模板未匹配变量索引必须为正整数{index} = " + num);
					}
				}
			}
			offset = next + 1;
			start = pattern.indexOf(B_CHAR, offset);
		}
		if (comps.size() == 0) {
			// 消息模板不存在变量界定符{}
			return new MessageFormatter(pattern, null, quiet);
		}
		if (offset != pattern.length()) {
			comps.add(new CompIndex(pattern.substring(offset), NO_VAR_REPLACE));
		}
		return new MessageFormatter(pattern, comps.toArray(new CompIndex[comps.size()]), quiet);
	}

	/**
	 * 格式化消息模板内容
	 * 
	 * @param pattern 模板内容
	 * @param args    变量数组
	 * @return 消息模板变量替换后内容
	 */
	public static String format(String pattern, Object... args) {
		if (pattern == null || pattern.length() == 0) {
			return pattern;
		}
		return of(pattern, true).build(args);
	}
}
